#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "array.h"

				    /* 
				       Dynamic arrays.
				     */

static struct array *cur_arr;	/* current array */

/* 
	   An array is created using |array_new| with the initial |capacity|
       and |size| of each element. If an invalid size is set,
|ARRAY_DEFAULT_CAPACITY| is assigned to |capacity|. */

#define ARRAY_DEFAULT_CAPACITY 0x1000	/* default number of array elements */

struct array *array_new(unsigned long long capacity, unsigned long long size)
{
	if (capacity == 0)
		capacity = ARRAY_DEFAULT_CAPACITY;
	assert(size > 0);

	cur_arr = (struct array *)calloc(1, sizeof(struct array));
	cur_arr->array = calloc(capacity, size);
	assert(cur_arr);
	cur_arr->len = 0;
	cur_arr->cap = capacity;
	cur_arr->size = size;

	return cur_arr;
}

/* The function |array_push| treats the |array| as a stack and put the
   element at the end. */

void *array_put(struct array *arr, const void *elem, unsigned long long i)
{
	assert(arr);
	assert(elem);
	assert(i >= 0 && i < arr->cap);

	memcpy(arr->array + i * arr->size, elem, arr->size);

	return arr->array + i * arr->size;
}

void *array_push(struct array *arr, const void *elem)
{
	assert(arr);
	assert(elem);

	arr->len++;

	/* Increase array capacity */

	if (arr->len >= arr->cap) {
		register void *a;	/* temporary pointer to array */
		a = arr->array;

		arr->cap += arr->cap;
		a = (unsigned long long *)realloc(a,
						  arr->cap *
						  sizeof(unsigned long long));
		if (a)
			arr->array = a;
	}

	return array_put(arr, elem, arr->len - 1);
}

	      /* Double the array capacity each time the limit is reached. */

void *array_get(struct array *arr, unsigned long long i)
{
	assert(arr);
	assert(i >= 0 && i < arr->cap);

	return arr->array + i * arr->size;
}

void array_free(struct array *arr)
{
	if (!arr)
		return;
	if (!arr->array)
		return;

	free(arr->array);
	free(arr);

	return;
}
